﻿/**@author W意波编写*/
#ifndef LK_MOBJECT_
#define LK_MOBJECT_
namespace LK
{
	/**
	@brief 表示一个封箱接口*/
	struct IMObject :Object
	{
		/**
		@brief 获取对象类型，这里比较特别：封箱对象总是返回PType::Make<MObjects>()*/
		PType GetType()const;
		/*operator&重载*/
		IMObject*operator&() { if (((Object*)this)->RefCount == 0)++(((Object*)this)->RefCount); return this; }
		IMObject const*operator&()const { if (((Object*)this)->RefCount == 0)++(((Object*)this)->RefCount); return this; }
		/**
		@breif 产生一个副本*/
		IMObject* Clone()const;
		/**
		@brief 判断是否副本*/
		bool IsCopy()const;
		/**
		@brief 获取内部保存的数据的指针，该方法用以直接修改封箱内实际存储的数据*/
		virtual void*GetDataPtr() { return NULL; }
		/**
		@brief 获取该对象所表示的数据的地址*/
		void* GetObjectPtr();
		/**
		@brief 获取封箱表示的数据类型*/
		PType GetInnerType()const;
	protected:
		/**
		@brief 内部数据类型*/
		PObject innerDataType;
		friend struct PMObjects;
	};
	/**
	@brief 表示一个封箱存储实体*/
	template<size_t size>struct MObject :IMObject {
		void* ptmp;//临时内容
		union {
			void* ptr;
			unsigned char data[size];//内容占用
		};
		MObject() :ptmp(NULL) {}
		void*GetDataPtr() { return data; }
		~MObject();
	};
	template<>struct MObject <0> :IMObject{ void*GetDataPtr() { return NULL; } };//空封箱对象
	struct PMObjects :PObject
	{
		/**@brief 复制构造函数*/
		inline PMObjects(PMObjects const&t) { PObject::SetTo(t.PObject::GetPtr()); }
		/**@brief 从对象指针构造*/
		inline PMObjects(IMObject const* p) { PObject::SetTo(StaticCastPointer(p)); }
		/**@brief 赋值*/
		inline PMObjects& operator=(PMObjects const&r) { PObject::SetTo(r.PObject::GetPtr()); return *this; }
		/**@brief 获取对象指针，并在对象指针为空时抛出异常*/
		inline IMObject* Ptr()const { return CheckPointer<IMObject>(PObject::GetPtr()); }
		/**@brief 获取对象指针*/
		inline IMObject* GetPtr()const { return CastPointer<IMObject>(PObject::GetPtr()); }
		/**@brief 重载operator->*/
		inline IMObject* operator->()const { return Ptr(); }
		/**@brief 检查对象引用计数如果不为1，则进行Clone。空引用将抛出异常*/
		inline IMObject* OnePtr() { IMObject* p = Ptr(); if (p->RefCount != 1) { PObject::SetTo(GetPtr()->Clone()); p = Ptr(); } return p; }
		/**@brief 获取对象类型*/
		inline PType GetType()const;
		/**@brief 默认构造空引用*/
		PMObjects() {}
		//添加类型信息
		static void AddTypeInfo();
		/**
		@brief 获取封箱表示的数据类型*/
		PType GetInnerType()const;
		/**
		@brief 获取内部数据指针，该方法常用以直接修改引用型封箱*/
		void*GetDataPtr()const;
		/**
		@brief 判断该封箱内容是否是原对象的副本
		@note 对于const&类型参数有可能会自动生成副本*/
		bool IsCopy()const;
		/**
		@brief 获取所表示的对象的指针，该方法常用以获取对象数值*/
		void*GetObjectPtr()const;
		/**
		@brief 通过指定的类型信息和该信息封箱实际存储数据的指针来构造一个封箱对象
		@note 如果pdat为NULL，则使用默认构造方法进行构造*/
		static PMObjects MakeMObjectByTypeInfo(PType const&, const void*pdat = NULL);
		/**
		@brief 通过指定的对象指针和类型信息和来构造一个封箱对象
		@note 如果pobj为NULL将抛出PPointerIsNullException异常
		@note 如果指定的type为左值引用，则会生成pobj所指向对象的副本*/
		static PMObjects MakeMObjectByTypeInfo(const void*pobj, PType const&);
		/**
		@brief 获取封箱数据
		@note 如果获取失败将抛出异常*/
		template <class T>T CastTo()const;
	};

}
#endif